package ObjectFile;

import IceAssembly.*;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Calendar;
      

/**
 * The ObjectFile class is responsible for creating the end object file from the several records that are involved.
 * @author peter
 */
public class ObjectFile {
    static public File link_object_file = new File("");
    static public int number_of_records = 0;
    static BufferedWriter bw;
    IceAssembly.Table table_instance = new IceAssembly.Table();
    IceAssembly.Convert convert_instance = new IceAssembly.Convert();
    LinkingRecord linking_record_instance = new LinkingRecord();
    
    /**
     * 
     */
    public void buildObjectFile(){     
        if(clearObjectFile()==0){
            return;
        }
        linking_record_instance.iniSymbolArray(table_instance.symbol_table,table_instance.symbol_row);
        appendHeaderRecord();
        appendLinkingRecord();
        appendTextRecords();
        appendEndRecord();
    }
    
    /**
    * Creates or clears the object file as a file we can write the object codes to.
    * <p>
    * <b>Change Log:</b><br>
    * 05/11/08 - Initial Code - Peter Dietz<br>
    * <p>
    * <b>Error Conditions Tested:</b><br>
    * INTERNAL: Writing to the object file is possible <br>
    * <p>
    * <b>Date of module being installed:</b> 05/11/08
    * <p><b>Original Author:</b>  Peter Dietz
    */
    public int clearObjectFile(){
        try{
            link_object_file.createNewFile();
            if(IceAssembly.Control.internal_debug.contentEquals("ON")){
                System.out.println(link_object_file.getAbsoluteFile());
            }
            bw = new BufferedWriter(new FileWriter(link_object_file));
            return 1;
        }catch(IOException e){
            System.out.println("Creating / clearing object file failed, check your path.");
            return 0;
        }
    }        
    
    /**
    * Appends the Header Record to the output file. The header record is the first row
    * in the output file.
    * Structure:<br>
     * H|startName|programLength|assignedStart|Dateyyy:ddd|Time hh:mm:ss|
     * numLinkReco|numText|exStart|ICE2|Version#|Revision#
    * <p>
    * <b>Change Log:</b><br>
    * 05/11/08 - Initial Code - Peter Dietz<br>
    * <p>
    * <b>Error Conditions Tested:</b><br>
    * none yet<br>
    * <p>
    * <b>Date of module being installed:</b> 05/11/08
    * <p><b>Original Author:</b>  Peter Dietz
    */
    public void appendHeaderRecord(){
        String start_label = table_instance.getAllLabels("START")[1];
        Calendar calendar_instance = Calendar.getInstance();
        
        
        String[] header = new String[12];
        header[0] = "H";
        header[1] = start_label;
        header[2] = new IceAssembly.Convert().intToFourHex(Table.intermediate_row);
        if(! table_instance.getLcOfLabel(start_label).contentEquals("-100")){
            header[3] = header[8]= convert_instance.intToFourHex(Integer.parseInt(table_instance.getLcOfLabel(start_label),16));
        }else{
            header[3] = header[8]= "0000";
        }
        
        header[4] = String.valueOf(calendar_instance.get(Calendar.YEAR)).concat(":").concat(String.valueOf(calendar_instance.get(Calendar.DAY_OF_YEAR)));
        
        String[] hh_mm_ss_string = new String[3];
            if(calendar_instance.get(Calendar.HOUR_OF_DAY) < 10){
                hh_mm_ss_string[0] = "0".concat(String.valueOf(calendar_instance.get(Calendar.HOUR_OF_DAY)));
            } else{
                hh_mm_ss_string[0] = String.valueOf(calendar_instance.get(Calendar.HOUR_OF_DAY));
            }
            if(calendar_instance.get(Calendar.MINUTE) < 10){
                hh_mm_ss_string[1] = "0".concat(String.valueOf(calendar_instance.get(Calendar.MINUTE)));
            } else{
                hh_mm_ss_string[1] = String.valueOf(calendar_instance.get(Calendar.MINUTE));
            }
            if(calendar_instance.get(Calendar.SECOND) < 10){
                hh_mm_ss_string[2] = "0".concat(String.valueOf(calendar_instance.get(Calendar.SECOND)));
            } else{
                hh_mm_ss_string[2] = String.valueOf(calendar_instance.get(Calendar.SECOND));
            }
        
        header[5] = hh_mm_ss_string[0].concat(":").concat(hh_mm_ss_string[1]).concat(":").concat(hh_mm_ss_string[2]);
        header[6] = convert_instance.intToFourHex(LinkingRecord.linking_record_array.length);
        header[7] = convert_instance.intToFourHex(Table.text_records_row);
        
        header[9] = "ICE2";
        header[10] = IceAssembly.Control.version_number;
        header[11] = IceAssembly.Control.revision_number;
        number_of_records++;
        try{
            for(int i=0;i<12;i++){
                bw.append(header[i]);
                if(i<11){
                    bw.append("|");
                }
            }
            bw.newLine();
        }catch(IOException e){
            System.out.println("Appending header record failed.");
        }
    }
    
    /**
    * Appends the Linking Records to the output file. Linking records are a subset 
    * of the symbol table that provides symbols usable by the linker for other programs.<br>
    * Structure:<br>
    * E|EntryName|EntryAddress|Type/Usage
    * <p>
    * <b>Change Log:</b><br>
    * 05/11/08 - Initial Code - Peter Dietz<br>
    * <p>
    * <b>Error Conditions Tested:</b><br>
    * none yet<br>
    * <p>
    * <b>Date of module being installed:</b> 05/11/08
    * <p><b>Original Author:</b>  Peter Dietz
    */
    public void appendLinkingRecord(){
        try{
            for(int index=0; index<LinkingRecord.linking_record_array.length; index++){
                number_of_records++;
                bw.append("L|"+LinkingRecord.linking_record_array[index][0]+"|"+LinkingRecord.linking_record_array[index][1]+"|"+LinkingRecord.linking_record_array[index][2]);
                bw.newLine();
            }
        }catch(Exception e){
            System.out.println("Appending linking records failed.");
        }
    }
    
   /**
    * Appends the Text Records to the output file. The Text Records are the twice 
    * assembled instructions or data records. There will be multiple entries.
    * Structure:<br>
    * T|LocationAddress|Debug|CodeDataWord|RelocationType|S1operator|S1symbol|S2operator|S2symbol
    * <p>
    * <b>Change Log:</b><br>
    * 05/11/08 - Initial Code - Peter Dietz<br>
    * <p>
    * <b>Error Conditions Tested:</b><br>
    * none yet<br>
    * <p>
    * <b>Date of module being installed:</b> 05/11/08
    * <p><b>Original Author:</b>  Peter Dietz
    */
    public void appendTextRecords(){
        TextRecord textrecord_instance = new TextRecord();
        textrecord_instance.createSP2TextRecords();
        try{
            for(int index=0; index<IceAssembly.Table.text_records_row; index++){
                number_of_records++;
                bw.append("T|"+IceAssembly.Table.text_records[index][0]+"|"+IceAssembly.Table.text_records[index][1]+"|"+IceAssembly.Table.text_records[index][2]+"|"+IceAssembly.Table.text_records[index][3]+"|"+IceAssembly.Table.text_records[index][4]+"|"+IceAssembly.Table.text_records[index][5]+"|"+IceAssembly.Table.text_records[index][6]+"|"+IceAssembly.Table.text_records[index][7]+"\n");
            }            
        }catch(Exception e){
            System.out.println("Appending Text records failed.");
        }
    }
    
   /**
    * Appends the End Record to the output file. The end record is the last row
    * of the output file.
    * Structure:<br>
     * H|TotalNumberOfRecords|startName
    * <p>
    * <b>Change Log:</b><br>
    * 05/11/08 - Initial Code - Peter Dietz<br>
    * <p>
    * <b>Error Conditions Tested:</b><br>
    * none yet<br>
    * <p>
    * <b>Date of module being installed:</b> 05/11/08
    * <p><b>Original Author:</b>  Peter Dietz
    */
    public void appendEndRecord(){
        number_of_records++;
        String[] end_record = new String[3];
        end_record[0] = "E";
        end_record[1] = convert_instance.intToFourHex(number_of_records);
        if(table_instance.getAllLabels("START")[0].contentEquals("-100")){
            end_record[2] = "";
        }else{
            end_record[2] = table_instance.getAllLabels("START")[1];
        }
        
        try{
            bw.append(end_record[0]+"|"+end_record[1]+"|"+end_record[2]);
            bw.newLine();
            bw.close();
        }catch(Exception e){
            System.out.println("Appending end record failed.");
        }
    }
   
    /**
     * 
     * @param args
     */
    public static void main(String[] args){
        try{
            IceAssembly.Control control_instance = new IceAssembly.Control();
            control_instance.main(args);
        }catch(Exception e){
            System.out.println("Exception occured in IceAssembly.Control.main function SP1");
        }
        
        try{
            ObjectFile object_file_instance = new ObjectFile();
            object_file_instance.buildObjectFile();
        }catch(Exception e){
            System.out.println("Exception occured in writing to object file");
        }
        
        try{
            SourceListing sourcelisting_instance = new SourceListing();
            sourcelisting_instance.ini_sourcelisting_array(Table.text_records);
        }catch(Exception e){
            System.out.println("Exception occured in writing to Sourcelisting file");
        }        
    }
}

